﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// sobel mode,
    /// choose between
    /// horizontal, vertical
    /// and both at once
    /// </summary>
    public enum Sobel_Mode
    {
        HORIZONTAL,
        DIAGONAL,
        VERTICAL
    }

    /// <summary>
    /// Sobel edge detection filter
    /// </summary>    
    public class Sobel : BaseImageFilter
    {
        /// <summary>
        /// 
        /// </summary>
        protected List<int[]> aIntHorizontal = new List<int[]>(){
                new int[]{-1,-2,-1},
                new int[]{0,0,0}, 
                new int[]{1,2,1},
                new int[]{1,0}
            };

        /// <summary>
        /// 
        /// </summary>
        protected List<int[]> aIntVertical = new List<int[]>(){
                new int[]{-1,0,1},
                new int[]{-2,0,2}, 
                new int[]{-1,0,1},
                new int[]{1,0}
            };

        /// <summary>
        /// 
        /// </summary>
        protected List<int[]> aIntDiagonal = new List<int[]>(){
                new int[]{-2,0,0},
                new int[]{-1,0,1}, 
                new int[]{0,1,2},
                new int[]{1,0}
            };

        protected Dictionary<Sobel_Mode, List<int[]>> m_aSobelMode = new Dictionary<Sobel_Mode, List<int[]>>();

        /// <summary>
        /// 
        /// </summary>
        protected Sobel_Mode m_Sobel_Mode = Sobel_Mode.DIAGONAL;

        /// <summary>
        /// default constructor
        /// </summary>
        public Sobel()
        {
            m_aSobelMode.Add(Sobel_Mode.VERTICAL, aIntVertical);
            m_aSobelMode.Add(Sobel_Mode.HORIZONTAL, aIntHorizontal);
            m_aSobelMode.Add(Sobel_Mode.DIAGONAL, aIntDiagonal);
        }

        /// <summary>
        /// constructor to specify sobel mode directly
        /// </summary>
        /// <param name="_mode"></param>
        public Sobel(Sobel_Mode _mode)
            : this()
        {
            m_Sobel_Mode = _mode;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Sobel"/> class.
        /// </summary>
        /// <param name="_sobel">The _sobel.</param>
        internal Sobel(Sobel _sobel)
        {
            this.m_Sobel_Mode = _sobel.m_Sobel_Mode;
        }

        /// <summary>
        /// Gets or sets the mode.
        /// </summary>
        /// <value>The mode.</value>
        public Sobel_Mode Mode
        {
            get { return m_Sobel_Mode; }
            set { m_Sobel_Mode = value; }
        }

        /// <summary>
        /// executes this filter
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            CConvMatrix matrix = new CConvMatrix();

            List<int[]> aInt = m_aSobelMode[m_Sobel_Mode];
            matrix.TopLeft = aInt[0][0];
            matrix.TopMid = aInt[0][1];
            matrix.TopRight = aInt[0][2];

            matrix.MidLeft = aInt[1][0];
            matrix.Pixel = aInt[1][1];
            matrix.MidRight = aInt[1][2];

            matrix.BottomLeft = aInt[2][0];
            matrix.BottomMid = aInt[2][1];
            matrix.BottomRight = aInt[2][2];

            matrix.Factor = aInt[3][0];
            matrix.Offset = aInt[3][1];
            new Convolution3x3(matrix).Execute(_bitmap);
            return _bitmap;
        }

        /// <summary>
        /// used to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Sobel(this);
        }
    }
}
